use crate::{db::connect_to_db, helpers::Bot};
use anyhow::{Context, Result};
use tokio_stream::StreamExt;
use mongodb::{
    bson::{doc, from_document, serde_helpers::uuid_as_binary},
    Database,
};
use teloxide::{
    prelude::*,
    types::{InlineKeyboardButton, InlineKeyboardButtonKind, InlineKeyboardMarkup, ReplyMarkup},
};
use uuid::Uuid;
pub async fn get_all_posts(bot: Bot, m: Message) -> Result<()> {
    let user_id = m.from().context("NoneError")?.id;
    let db = connect_to_db().await?;
    let user = crate::handlers::get_user(user_id).await?;
    let user_posts = get_all_user_posts(user.id, 0, &db).await?;
    let mut posts = Vec::with_capacity(50);
    for user_post in user_posts {
        let given_post = get_post(&db, user_post.post_id).await?;
        let post = PostGetAllPosts {
            id: given_post.id,
            title: given_post.title,
            url: user_post.original_url,
        };
        posts.push(post);
    }
    let mut button_posts = Vec::with_capacity(51);
    for post in posts {
        let button_name = {
            if let Some(title) = &post.title {
                title
            } else {
                &post.url
            }
        };
        button_posts.push(vec![InlineKeyboardButton::new(
            button_name,
            InlineKeyboardButtonKind::CallbackData(format!("post {} 1", post.id.to_hyphenated())),
        )]);
    }
    button_posts.push(vec![
        InlineKeyboardButton::new(
            "<-",
            InlineKeyboardButtonKind::CallbackData("page 0".to_string()),
        ),
        InlineKeyboardButton::new(
            "->",
            InlineKeyboardButtonKind::CallbackData("page 2".to_string()),
        ),
    ]);
    bot.send_message(user_id, "All your posts:")
        .reply_markup(ReplyMarkup::InlineKeyboard(InlineKeyboardMarkup::new(
            button_posts.clone(),
        )))
        .await?;
    Ok(())
}

#[derive(Serialize, Deserialize, Debug)]
pub struct PostGetAllPosts {
    #[serde(with = "uuid_as_binary")]
    pub id: Uuid,
    pub title: Option<String>,
    pub url: String,
}
pub async fn get_all_user_posts(user_id: Uuid, _pos: i32, db: &Database) -> Result<Vec<UserPost>> {
    let coll = db.collection::<UserPost>("userposts");
    let match_aggr = doc! {
        "$match": {
        "user_id": user_id
        }
    };
    let proj_aggr = doc! {
        "$project" :{
            "post_id": 1_i32,
            "original_url": 1_i32
        }
    };
    let limit_aggr = doc! {
      "$limit": 50_i32
    };
    let pipeline = [match_aggr, proj_aggr, limit_aggr];
    let mut cursor = coll.aggregate(pipeline, None).await?;
    let mut posts = Vec::with_capacity(50);
    while let Some(post) = cursor.next().await {
        posts.push(from_document::<UserPost>(post?)?)
    }
    Ok(posts)
}
use mongodb::{
    bson::{spec::BinarySubtype, Binary},
    options::FindOneOptions,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct UserPost {
    #[serde(with = "uuid_as_binary")]
    pub post_id: Uuid,
    pub original_url: String,
}
pub async fn get_post(db: &Database, post_id: Uuid) -> Result<PostGetAllPostsDb> {
    let bin_id = Binary {
        subtype: BinarySubtype::Uuid,
        bytes: post_id.as_bytes().to_vec(),
    };
    let coll = db.collection::<PostGetAllPostsDb>("posts");
    let filter = doc! {
        "id": bin_id,
    };
    let projection = doc! {
        "title":1,
        "id":1,
    };

    let options = FindOneOptions::builder().projection(projection).build();
    let post = coll.find_one(filter, options).await?.context("lalala")?;
    Ok(post)
}

#[derive(Serialize, Deserialize, Debug)]
pub struct PostGetAllPostsDb {
    #[serde(with = "uuid_as_binary")]
    pub id: Uuid,
    pub title: Option<String>,
}
